import numpy as np
import math
import matplotlib.pyplot as plt


def handleData(data):
    """处理数据,这里插入1.0,是因为回归是wx=b,w0=b"""
    for i in range(len(data)):
        data[i].insert(0, 1.0)

    return np.array(data)


def sigmoid(x):
    """sigmoid函数"""
    return 1.0 / (1 + np.exp(-x))


def optimization(data, alpha=0.01, iterations=1000):
    """
    优化似然函数，使用梯度下降
    :param data: 数据矩阵
    :param alpha: 步长
    :param iterations: 迭代次数
    :return: 权重
    """
    datamat = data[:, :-1]
    labelmat = data[:, -1:]
    _, col = datamat.shape
    w = np.ones((col, 1))
    for i in range(iterations):
        h = sigmoid(np.dot(datamat, w))
        error = labelmat - h
        gradient = np.dot(datamat.T, error)
        w = w + alpha * gradient
    return w


if __name__ == '__main__':
    p = 0.5
    origi_data = [
        [-0.017612, 14.053064, 0],
        [-1.395634, 4.662541, 1],
        [-0.752157, 6.538620, 0],
        [-1.322371, 7.152853, 0],
        [0.423363, 11.054677, 0],
        [0.406704, 7.067335, 1],
        [0.667394, 12.741452, 0],
        [-2.460150, 6.866805, 1],
        [0.569411, 9.548755, 0],
        [-0.026632, 10.427743, 0],
        [0.850433, 6.920334, 1],
        [1.347183, 13.175500, 0],
        [1.176813, 3.167020, 1],
        [-1.781871, 9.097953, 0]
    ]
    w = optimization(handleData(origi_data))
    w0 = w[0]
    w1 = w[1]
    w2 = w[2]

    # 输出分类的标签
    for row in origi_data:
        tmp = row[0] * w[0] + row[1] * w[1] + row[2] * w[2]
        if math.exp(tmp[0]) / (1 + math.exp(tmp[0])) >= 0.5:
            print(1)
        else:
            print(0)

    x1 = np.arange(-3, 3, 0.01)
    odds = p / (1 - p)
    x2 = (math.log(odds) - w1 * x1 - w0) / w2

    data = np.array(origi_data)[:, 1:]
    row, col = data.shape
    plt.figure()
    plt.plot(x1, x2, c='orange')
    for i in range(row):
        if data[i][2] == 0:
            plt.scatter(data[i][0], data[i][1], c='blue')
        else:
            plt.scatter(data[i][0], data[i][1], c='red')
    plt.xlabel('x1')
    plt.ylabel('x2')

    plt.show()